<?php

class microconfig {
	function microconfig($configfile, $hosts='')
	{
		$this->_configfile = $configfile;
		$this->_hosts = is_array($hosts) ? $hosts : array();
		$cfile = dirname($this->_configfile) . '/' . basename(strtolower($this->_configfile), '.php') . '.cfg.php';
		if(file_exists($cfile))
		{
			include_once($cfile);
			if(isset($micro_cfg))
			{
				if($options = get_object_vars($micro_cfg))
				{
					foreach($options as $o_name => $o_value)
					{
						if($o_name{0} != '_')	
						{
							$this->$o_name = $o_value;
						}
					}
					$this->_options = $options;
				}
			}
		}
		$this->process_subdomains();
	}
	
	function switch_to_raw()
	{
		foreach((array)$this->_options as $o_name => $o_value)
		{
			if($o_name{0} != '_')	
			{
				$this->$o_name = $o_value;
			}
		}
	}
	
	function process_subdomains()
	{
		if(isset($this->_hosts[$_SERVER['HTTP_HOST']])) {
			$this->_subdomain = $this->_hosts[$_SERVER['HTTP_HOST']];
			$this->_isdomain = true;
			$this->_domain = $_SERVER['HTTP_HOST'];
		}
		else {
			$this->_isdomain = false;
			$dparts = explode('.', $_SERVER['HTTP_HOST']);
			if(preg_match('/\\.[^\\.]+\\.[a-z]{2,3}$/i', trim($_SERVER['HTTP_HOST']))) {
				$this->_subdomain = preg_replace('/\\.[^\\.]+\\.[a-z]{2,3}$/i', '', $_SERVER['HTTP_HOST']);
			}
			else {
				$this->_subdomain = '';
			}
		} 
		$needles = array('{{subdomain.}}', '{{subdomain}}');
		$replacements = array(($this->_subdomain == '')?'': $this->_subdomain . '.', $this->_subdomain); 
		if($options = get_object_vars($this))
		{
			foreach($options as $o_name => $o_value)
			{
				if($o_name{0} != '_')	
				{
					$this->$o_name = str_replace($needles, $replacements, $o_value);
				}
			}
		}
	}

	function get_config_descriptions()
	{
		$thisfile = implode('', file($this->_configfile));
		preg_match("|/\* BEGIN CONFIG VARS \*/(.*)/\* END CON" . "FIG VARS \*/|ims", $thisfile, $matches);
		preg_match_all('/var \\$([a-z_]*) = ((\\"([^\\"]|\\\\\\")*\\")|(true|false|[0-9]+)); \/\/(.*)/i', $matches[1], $descs, PREG_SET_ORDER);
		foreach($descs as $desc)
		{
			$opts = explode(':', $desc[6]);
			$newdescs[$desc[1]]['description'] = $opts[0];
			$newdescs[$desc[1]]['format'] = trim($opts[1]);
			$newdescs[$desc[1]]['value'] = $this->$desc[1];
		}
		return $newdescs;
	}

	function write_post()
	{
		return $this->write($_POST);
	}

	function write($newoptions)
	{
		$options = get_object_vars($this);
		if(!isset($newoptions['config'])) return false;

		$cdesc = $this->get_config_descriptions();

		$outputvars = '';
		$thisfile = '';
		foreach($options as $o_name => $o_value)
		{
			if(isset($newoptions[$o_name]))
			{
				$o_value = $newoptions[$o_name];
				if(!is_array($o_value)) $o_value = stripslashes($o_value);
				if($o_value == 'false' || $o_value == 'true')
				{
					$this->$o_name = ($o_value == 'true') ? true : false;
				}
				else if(is_numeric($o_value))
				{
					$this->$o_name = 0 + $o_value;
				}
				else
				{
					$this->$o_name = $o_value;
				}
			}
		}

		unset($this->_options);
		$thisfile = '<'.'?php $micro_cfg=unserialize("' . addslashes(serialize($this)) . '");?'.'>';

		$cfile = dirname($this->_configfile) . '/' . basename(strtolower($this->_configfile), '.php') . '.cfg.php';
		if((!file_exists($cfile) || is_writable($cfile)) && ($h = @fopen($cfile, 'w')))
		{
			fwrite($h, $thisfile);
			fclose($h);
			$this->process_subdomains();
			return true;
		}
		else
		{
			echo "Config file '{$cfile}' not write-enabled.";
			$this->_thisfile = htmlentities($thisfile);
			$this->process_subdomains();
			return false;
		}
	}

	function editform($echo = false)
	{
		$options = get_object_vars($this);

		$cdesc = $this->get_config_descriptions();
		$output = '<form method="post"><dl>';
		foreach($options as $o_name => $o_value)
		{
			if($o_name{0} != '_')
			{
				if($cdesc[$o_name]['format'] == '')
				{
					$output .= '<dt>' . trim($cdesc[$o_name]['description']) . ":</dt>\n<dd><input type=\"text\" name=\"{$o_name}\" value=\"{$o_value}\" /></dd>\n";
				}
				else if($cdesc[$o_name]['format'] == 'TEXTAREA')
				{
					$output .= '<dt>' . trim($cdesc[$o_name]['description']) . ":</dt>\n<dd><textarea style=\"width:400px;height:100px;\" name=\"{$o_name}\">{$o_value}</textarea></dd>\n";
				}
				else
				{
					$opts = explode(',', $cdesc[$o_name]['format']);
					$output .= '<dt>' . $cdesc[$o_name]['description'] . ":</dt>\n<dd>\n";
					foreach($opts as $opt)
					{
						$sopt = trim($opt, "'\"");
						$output .= "<label><input type=\"radio\" name=\"{$o_name}\" value=\"{$opt}\" ";
						$value = $cdesc[$o_name]['value'];
						if($opt == 'true' || $opt == 'false')
						{
							if(($opt == 'true') && ($value === true)) $output .= 'checked="checked" ';
							if(($opt == 'false') && ($value === false)) $output .= 'checked="checked" ';
						}
						else if($value == $opt)
						{
							$output .= 'checked="checked" ';
						}
						$output .= "/>{$sopt}</label><br/>\n";
					}
					$output .= "</dd>\n";
				}
			}
		}
		$output .= "</dl>
		<input type=\"submit\" name=\"Submit\" value=\"Commit Changes\" />
		<input type=\"hidden\" name=\"config\" value=\"editform\" />
		</form>
		";
		if($echo) echo $output;
		return $output;
	}

	var $_thisfile;
	var $_configfile;
}


class microsession {

	var $_sessionname;
	var $_bad_login = false;

	function microsession($sessionname)
	{
		$session = @unserialize(@gzuncompress(@base64_decode($_COOKIE[$sessionname])));
		$vars = get_object_vars($session);
		if(is_array($vars))
		{
			foreach($vars as $name => $value)
			{
				$this->$name = $value;
			}
		}
		$this->_sessionname = $sessionname;
		$this->activate_session();
		ob_start();
		//echo '<pre>'.print_r($_sessionname,1).'</pre>';
	}
	
	function activate_session()
	{
	// Virtual function
	}

	function save($sessionname = '')
	{
		if($sessionname == '') $sessionname = $this->_sessionname;
		$vars = get_object_vars($this);
		foreach($vars as $name => $value) {
			if($name{0} != '_')	$session->$name = $value;
		}

		setcookie($sessionname, base64_encode(gzcompress(serialize($session))), time()+60*60*6, '/');
	}

	function is_auth()
	{
	  if($this->_bad_login) return false;
	  
		global $cookiehash, $current_user;
		if(function_exists('get_currentuserinfo')) get_currentuserinfo();
		
		$auth = false;
		$login = array();
		/*
		if(!empty($current_user)) {		  
			$login['wp']->user = $current_user->user_login;
			$login['wp']->pass = $current_user->user_pass;
		}
		if(isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
			$login['auth']->user = $_SERVER['PHP_AUTH_USER'];
			$login['auth']->pass = $_SERVER['PHP_AUTH_PW']; 
		}
		*/
		if(isset($_POST['microsession_user']) && isset($_POST['microsession_pass'])) {
			$login_user = $_POST['microsession_user'];
			$login_pass = $_POST['microsession_pass'];
		}
		else if(isset($this->session_password)) {
			$login_user = $this->session_username;
			$login_pass = $this->session_password;
		}		
		
	  $a = $this->do_auth($login_user, $login_pass);
		if(wlToolkit::isError($a)) {
		  $this->_bad_login = true;
		  return false;
		} else {
			$this->session_username = $login_user;
			$this->session_password = $login_pass;
			$this->save();
			$auth = true;
		}
				
		return $auth;
	}

	function auth_form($fn = false)
	{
		$auth = $this->is_auth();
		if(!$auth)
		{
			if(is_callable($fn))
			{
				$fn();
			}
			else
			{
				$this->login_form();
			}
		}
		return $auth;
	}

	function do_auth($user, $pass, $level = 0) //virtual
	{
	  //new wp
	  if(function_exists('wp_signon'))
	  {
	    $sign = wp_signon(array(
	      'user_login' => $user,
	      'user_password' => $pass
	    ));
	    
	    if(is_wp_error($sign))
	    {
	      wlRequest::getInstance()->setWordpressError($sign);
	      return false;
	    }
	    
	    if(! $sign->has_cap($level))
	    {
	      wlRequest::getInstance()->setError('no-capability', 'You don\'t have the permission to perform this action');
	      return false;
	    }
	    	    
	    return true;
	  //older wp (FIXME: very old? should we support this?)
	  } else if(function_exists('get_userdatabylogin'))
		{
			global $wpdb, $current_user;
			$userdata = get_userdatabylogin($user);
			$userobj = new WP_User($userdata->ID);
			//owd($user, $pass, md5($userdata->user_pass), $userobj->has_cap($level));
			if(md5($pass) == md5($userdata->user_pass))
			{
			  if(! $userobj->has_cap($level))
			  {
			    wlRequest::getInstance()->setError('no-capability', 'You don\'t have the permission to perform this action');
			    return false;
			  }
			    
			  return true;
			}
		} else
		{
			$this->session_username = $user;
			$this->session_password = $pass;
			$this->save();
			return false;
		}
	}

	function login_form()
	{
		if(isset($_POST['microsession_user']))
		{
			echo "<div id=\"specialmessage\">Sorry, that login is incorrect.</div>";
		}
		echo "<form id=\"microauth\" method=\"post\">\n";
		echo "<dl><dt>Username:</dt><dd><input type=\"text\" name=\"microsession_user\" value=\"{$this->session_username}\" /></dd>\n";
		echo "<dt>Password:</dt><dd><input type=\"password\" name=\"microsession_pass\" value=\"{$this->session_password}\" /></dd></dl>\n";
		echo "<input type=\"submit\" name=\"submit\" value=\"Log In\" />\n";
		echo "</form>";
	}
	
	function end_session()
	{
		$this->session_username = '';
		$this->session_password = '';
		$this->save();
	}
}



/* DATABASE SUPPORT FUNCTIONS */
class microdb {

	var $pdb;
	var $dberror;
	var $lastquery;
	var $queries = array();

	function microdb($config)
	{
		if($config->regusersonly == 'WordPress') {
			$config->db_server = DB_HOST;
			$config->db_user = DB_USER;
			$config->db_password = DB_PASSWORD;
			$config->db_name = DB_NAME;
		}

		if(!($this->pdb = @mysql_connect($config->db_server, $config->db_user, $config->db_password))) {
			$this->dberror = "Database server, username, or password is incorrect.";
			return false;
		}
		else {
			if(!(mysql_select_db($config->db_name, $this->pdb))) {
				$this->dberror = "Specified user does not have access to a database with that name on the server.";
				return false;
			}
		}
		return true;
	}

	function query($qry)
	{
		$timestart = time();
		$this->lastquery = $qry;
		$tableres = @mysql_query($qry, $this->pdb);
		$err = mysql_error();
		$this->queries[] = array($qry, $timestart, time());
		if($err != '') {
			$this->dberror = $err;
			return false;
		}
		return true;
	}

	function get_results($qry, $type='object')
	{
		$timestart = time();
		$this->lastquery = $qry;
		$tableres = @mysql_query($qry, $this->pdb);
		$err = @mysql_error($this->pdb);
		$this->queries[] = array($qry, $timestart, time());
		if($err != '') {
			$this->dberror = $err;
			return false;
		}
		$ary = array();
		switch($type)
		{
		case 'object': $fn = 'mysql_fetch_object'; break;
		case 'row': $fn = 'mysql_fetch_row'; break;
		case 'assoc': $fn = 'mysql_fetch_assoc'; break;
		}
		while($row = @$fn($tableres))
		{
			$ary[] = $row;
		}
		return $ary;
	}

	function get_row($qry, $type='object')
	{
		$timestart = time();
		$this->lastquery = $qry;
		$tableres = @mysql_query($qry, $this->pdb);
		$err = @mysql_error($this->pdb);
		$this->queries[] = array($qry, $timestart, time());
		if($err != '') {
			$this->dberror = $err;
			return false;
		}
		switch($type)
		{
		case 'object': $fn = 'mysql_fetch_object'; break;
		case 'row': $fn = 'mysql_fetch_row'; break;
		case 'assoc': $fn = 'mysql_fetch_assoc'; break;
		}
		return @$fn($tableres);
	}

	function get_col($qry, $index = 0)
	{
		$timestart = time();
		$this->lastquery = $qry;
		$tableres = @mysql_query($qry, $this->pdb);
		$err = @mysql_error($this->pdb);
		$this->queries[] = array($qry, $timestart, time());
		if($err != '') {
			$this->dberror = $err;
			return false;
		}
		$ary = array();
		while($row = @mysql_fetch_array($tableres, MYSQL_BOTH))
		{
			$ary[] = $row[$index];
		}
		return $ary;
	}

	function get_var($qry)
	{
		$timestart = time();
		$this->lastquery = $qry;
		$tableres = @mysql_query($qry, $this->pdb);
		$this->queries[] = array($qry, $timestart, time());
		if($tableres)
		{
			$err = mysql_error($this->pdb);
			if($err != '') {
				$this->dberror = $err;
				return null;
			}
			$ary = mysql_fetch_row($tableres);
			return $ary[0];
		}
		else
		{
			$err = @mysql_error($this->pdb);
			if($err != '') {
				$this->dberror = $err;
				return null;
			}
			return null;
		}
	}

	function insert_id()
	{
		return mysql_insert_id($this->pdb);
	}

	function get_error($echo = false)
	{
		$res = "<div style=\"border:1px dashed red;background-color:#FCC;width:100%;\">{$this->dberror}<hr style=\"color:red;\" />{$this->lastquery}</div>";
		if($echo) owd($this->dberror, $this->lastquery);
		return $res;
	}

	function result_table($qry, $tableid = '', $showcolumns = null, $headings = null)
	{
		$tableid = "id=\"{$tableid}\"";
		echo "<table {$tableid}>\n";
		if(is_string($qry))
		{
			$results = $this->get_results($qry, 'assoc');
		}
		else
		{
			$results = $qry;
		}
		if($results)
		{
			if($showcolumns == null)
			{
				$showcolumns = array_keys($results[0]);
			}
			if($headings == null)
			{
				$headings = $showcolumns;
			}
			echo "<thead><tr>\n";
			foreach($headings as $heading)
			{
				echo "<th>{$heading}</th>\n";
			}
			echo "</tr></thead>\n";
			echo "<tbody>\n";
			foreach($results as $result)
			{
				echo "<tr>\n";
				foreach($showcolumns as $column)
				{
					echo "<td>{$result[$column]}</td>\n";
				}
				echo "</tr>\n";
			}
			echo "</tbody>\n";
		}
		else
		{
			echo "<tr><td>No results</td></tr>";
		}
		echo "</table>";
	}

	function table_exists($tablename)
	{
		$tables = $this->get_col('SHOW TABLES;');
		return $tables && in_array($tablename, $tables);
	}

	function upgrade($queries, $execute = true, $silent = true) {
		if( !is_array($queries) ) {
			$queries = explode( ';', $queries );
			if('' == $queries[count($queries) - 1]) array_pop($queries);
		}

		$cqueries = array();
		$iqueries = array();
		$for_update = array();

		foreach($queries as $qry) {
			if(preg_match("|CREATE TABLE ([^ ]*)|", $qry, $matches)) {
				$cqueries[strtolower($matches[1])] = $qry;
				$for_update[$matches[1]] = 'Created table '.$matches[1];
			}
			else if(preg_match("|CREATE DATABASE ([^ ]*)|", $qry, $matches)) {
				array_unshift($cqueries, $qry);
			}
			else if(preg_match("|INSERT INTO ([^ ]*)|", $qry, $matches)) {
				$iqueries[] = $qry;
			}
			else if(preg_match("|UPDATE ([^ ]*)|", $qry, $matches)) {
				$iqueries[] = $qry;
			}
			else {
				// Unrecognized query type
			}
		}

		if($tables = $this->get_col('SHOW TABLES;')) {
			foreach($tables as $table) {
				if( array_key_exists(strtolower($table), $cqueries) ) {
					unset($cfields);
					unset($indices);
					preg_match("|\((.*)\)|ms", $cqueries[strtolower($table)], $match2);
					$qryline = trim($match2[1]);

					$flds = explode("\n", $qryline);
					foreach($flds as $fld) {
						preg_match("|^([^ ]*)|", trim($fld), $fvals);
						$fieldname = $fvals[1];
						$validfield = true;
						switch(strtolower($fieldname))
						{
						case '':
						case 'primary':
						case 'index':
						case 'fulltext':
						case 'unique':
						case 'key':
							$validfield = false;
							$indices[] = trim(trim($fld), ", \n");
							break;
						}
						$fld = trim($fld);
						if($validfield) {
							$cfields[strtolower($fieldname)] = trim($fld, ", \n");
						}
					}
					$tablefields = $this->get_results("DESCRIBE {$table};");
					foreach((array)$tablefields as $tablefield) {
						if(array_key_exists(strtolower($tablefield->Field), $cfields)) {
							preg_match("|".$tablefield->Field." ([^ ]*( unsigned)?)|i", $cfields[strtolower($tablefield->Field)], $matches);
							$fieldtype = $matches[1];
							if($tablefield->Type != $fieldtype) {
								$cqueries[] = "ALTER TABLE {$table} CHANGE COLUMN {$tablefield->Field} " . $cfields[strtolower($tablefield->Field)];
								$for_update[$table.'.'.$tablefield->Field] = "Changed type of {$table}.{$tablefield->Field} from {$tablefield->Type} to {$fieldtype}";
							}
							if(preg_match("| DEFAULT '(.*)'|i", $cfields[strtolower($tablefield->Field)], $matches)) {
								$default_value = $matches[1];
								if($tablefield->Default != $default_value)
								{
									$cqueries[] = "ALTER TABLE {$table} ALTER COLUMN {$tablefield->Field} SET DEFAULT '{$default_value}'";
									$for_update[$table.'.'.$tablefield->Field] = "Changed default value of {$table}.{$tablefield->Field} from {$tablefield->Default} to {$default_value}";
								}
							}
							unset($cfields[strtolower($tablefield->Field)]);
						}
						else {
							// This field exists in the table, but not in the creation queries?
						}
					}
					foreach($cfields as $fieldname => $fielddef) {
						$cqueries[] = "ALTER TABLE {$table} ADD COLUMN $fielddef";
						$for_update[$table.'.'.$fieldname] = 'Added column '.$table.'.'.$fieldname;
					}
					$tableindices = $this->get_results("SHOW INDEX FROM {$table};");

					if($tableindices) {
						unset($index_ary);
						foreach($tableindices as $tableindex) {
							$keyname = $tableindex->Key_name;
							$index_ary[$keyname]['columns'][] = array('fieldname' => $tableindex->Column_name, 'subpart' => $tableindex->Sub_part);
							$index_ary[$keyname]['unique'] = ($tableindex->Non_unique == 0)?true:false;
						}
						foreach($index_ary as $index_name => $index_data) {
							$index_string = '';
							if($index_name == 'PRIMARY') {
								$index_string .= 'PRIMARY ';
							}
							else if($index_data['unique']) {
								$index_string .= 'UNIQUE ';
							}
							$index_string .= 'KEY ';
							if($index_name != 'PRIMARY') {
								$index_string .= $index_name;
							}
							$index_columns = '';
							foreach($index_data['columns'] as $column_data) {
								if($index_columns != '') $index_columns .= ',';
								$index_columns .= $column_data['fieldname'];
								if($column_data['subpart'] != '') {
									$index_columns .= '('.$column_data['subpart'].')';
								}
							}
							$index_string .= ' ('.$index_columns.')';

							if(!(($aindex = array_search($index_string, $indices)) === false)) {
								unset($indices[$aindex]);
							}
						}
					}
					foreach($indices as $index) {
						$cqueries[] = "ALTER TABLE {$table} ADD $index";
						$for_update[$table.'.'.$fieldname] = 'Added index '.$table.' '.$index;
					}
					unset($cqueries[strtolower($table)]);
					unset($for_update[strtolower($table)]);
				} else {
				}
			}
		}

		$allqueries = array_merge($cqueries, $iqueries);
		if($execute) {
			foreach($allqueries as $query) {
				if(!$this->query($query))
				{
					$this->get_error(true);
					return false;
				}
			}
		}

		if(!$silent)
		{
			if(count($for_update) > 0)
			{
				echo "<ul>\n";
				foreach($for_update as $upgrade)
				{
					echo "<li>{$upgrade}</li>\n";
				}
				echo "</ul>\n";
			}
			else
			{
			echo "<ul><li>No Upgrades</li></ul>";
			}
		}

		return $for_update;
	}
	
	function escape()
	{
		$args = func_get_args();
		
		if (function_exists('mysql_real_escape_string')) {
			if(count($args) == 1) return @mysql_real_escape_string($args[0]);
			return @array_map('mysql_real_escape_string', $args);
		}
		if(count($args) == 1)	return mysql_escape_string($args[0]);
		return array_map('mysql_escape_string', $args);
	}
}

/*
Parameters:
modify_qs(newkey, newvalue, oldquery_or_uri) or
modify_qs(associative_array, oldquery_or_uri)
*/
function modify_qs() {

	$REQUEST_URI = ( isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : $_SERVER['SCRIPT_NAME'] . (( isset($_SERVER['QUERY_STRING']) ? '?' . $_SERVER['QUERY_STRING'] : '')));


	$ret = '';
	if(is_array(func_get_arg(0))) {
		if (@func_num_args() < 2) {
			$uri = $REQUEST_URI;
		} else {
			$uri = @func_get_arg(1);
		}
	}
	else {
		if (@func_num_args() < 3) {
			$uri = $REQUEST_URI;
		} else {
			$uri = @func_get_arg(2);
		}
	}

	if (strstr($uri, '?')) {
		$parts = explode('?', $uri, 2);
		if (1 == count($parts)) {
			$base = '?';
			$query = $parts[0];
		}
		else {
			$base = $parts[0] . '?';
			$query = $parts[1];
		}
	}
	else {
		$base = $uri . '?';
		$query = '';
	}
	parse_str($query, $qs);
	if (is_array(func_get_arg(0))) {
		$kayvees = func_get_arg(0);
		$qs = array_merge($qs, $kayvees);
	}
	else
    {
			$qs[func_get_arg(0)] = func_get_arg(1);
    }

	foreach($qs as $k => $v)
    {
			if($v != '')
        {
					if($ret != '') $ret .= '&';
					$ret .= "$k=$v";
        }
    }
	$ret = $base . $ret;
	return trim($ret, '?');
}

function remove_qs($url = '') {
	$REQUEST_URI = ( isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : $_SERVER['SCRIPT_NAME'] . (( isset($_SERVER['QUERY_STRING']) ? '?' . $_SERVER['QUERY_STRING'] : '')));
	if($url == '') $url = $REQUEST_URI;
	if(strpos($url, '?') !== false) {
		return substr($url, 0, strpos($url, '?'));
	}
	return $url;
}

function match_scheme($url, $newscheme = '')
{
	$purl = parse_url($url);
	
	$scheme = ($_SERVER["HTTPS"] == 'on')?'https':'http';
	if($purl['query'] != '') $purl['query'] = '?' . $purl['query'];
	if($newscheme != '') $scheme = $newscheme;
	return "{$scheme}://{$purl['host']}{$purl['path']}{$purl['query']}";
}


class microrewrite {
	var $rules = array();
	var $links = array();
	var $basename = '';
	var $httpsname = '';
	var $using_rewrite = false;

	function compact($dorewrite = false)
	{	
		$setvars = array();
		$stub = ( isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : $_SERVER['SCRIPT_NAME'] . ( isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '') . ( (isset($_SERVER['QUERY_STRING']) && ($_SERVER['QUERY_STRING'] != '')) ? '?' . $_SERVER['QUERY_STRING'] : ''));
		$base = parse_url($this->base());
		if($base['path'] != '') 
			$stub = substr($stub, strpos($stub, $base['path']) + strlen($base['path']));
		$stub = urldecode($stub);
		if(substr(@$_GET['stub'],0,2) != '//') {
			if($_SERVER['QUERY_STRING'] != '')
				$stub = substr($stub, 0, strlen($stub) - strlen($_SERVER['QUERY_STRING']) - 1);
			if(isset($_GET['stub'])) $stub = $_GET['stub'];
		}
		$this->stub = $stub;
		foreach($this->rules as $rulename => $rule)
		{
			$vars = explode(',', $rule[1]);
			foreach($vars as $varname)
			{
				if(isset($_GET[$varname]))
				{
					$setvars[$varname] = $_GET[$varname];
				}
			}

			if($dorewrite && preg_match($rule[0], $stub, $matches))
			{
				for($z=0;$z<count($vars);$z++)
				{
						$setvars[$vars[$z]] = $matches[$z+1];
					if(isset($_GET[$vars[$z]])) $setvars[$vars[$z]] = $_GET[$vars[$z]];
				}
				$this->using_rewrite = true;
				$this->ruleresults['match'][] = $rulename;
				break;
			}
			else
			{
				$this->ruleresults['nomatch'][] = $rulename;
			}
		}
		foreach($setvars as $key=>$var) {
			$outvars[$key] = $this->infilter($key, $var);
		}
		$this->setvars = $outvars;
		return $outvars;
	}
	
	function get_link($linkary, $forcesecure = false)
	{
		$topscore = -1;
		$linkmatch = '';
		$matchary = array();
		foreach($this->links as $link)
		{
			preg_match_all('/%([^%]+)%/', $link, $matches);
			$thisscore = 0;
			foreach($matches[1] as $insertion)
			{
				if(array_key_exists($insertion, $linkary)) $thisscore ++;
			}
			$thisscore -= abs(count($matches[1]) - count($linkary));
			if(count($matches[1]) > 0)
			{
				$thisscore = $thisscore / count($linkary);
			}
			else
			{
				$thisscore = 0;
			}
			if($thisscore > $topscore)
			{
				$topscore = $thisscore;
				$linkmatch = $link;
				$matchary = $matches[1];
			}
		}

		$missing = array_diff(array_keys($linkary), $matchary);		
		$outlink = $this->base($forcesecure) . preg_replace('/%([^%]+)%/e', '\$this->outfilter(\'\\1\', \$linkary[\'\\1\'])', $linkmatch);
		if(count($missing) > 0)
		{
			$featurechar = '?';
			foreach($missing as $miss)
			{
				$outlink .= "{$featurechar}{$miss}={$linkary[$miss]}";
				$featurechar = '&';
			}
		}
		$outlink = str_replace(' ', '+', $outlink);
		return $outlink;
	}
	
	function outfilter($piecename, $value)  //Virtual
	{
		return $value;
	}

	function infilter($piecename, $value)  //Virtual
	{
		return $value;
	}
	
	function init_rules()  //Virtual
	{
	}
	
	function is_secure()
	{
		return (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on');
	}
	
	function url_dir($dir)
	{
		$info = parse_url($dir);
		extract($info);
		$path = dirname($path);
		return "{$scheme}://{$host}{$path}";
	}
	
	function base($forcesecure = false)
	{
		return (($this->is_secure() && ($this->httpsname != '')) || $forcesecure) ? $this->httpsname : $this->basename;
	}
	
	function microrewrite($basename, $httpsname = '')
	{
		$this->basename = $basename;
		$this->httpsname = $httpsname;
		$this->init_rules();
	}
}

class microtemplate {
	var $template;
	var $fields = array();
	
	function microtemplate($template) {
		$this->template = $template;
	}
	
	function set_field($name, $value) {
		$this->fields[$name] = $value;
	}
	
	function regex_map_field($value) {
		return "/<!--{$value}-->/i";
	}

	function render($clear = true) {
		$tests = array_map(array(&$this, 'regex_map_field') , array_keys($this->fields));
		$output = preg_replace($tests, $this->fields, $this->template);
		while(preg_match('/<!--if(not)?:(.*?)-->(.*?)<!--\/if\\1?:\\2-->/si', $output, $match)) {
			$rematch = str_replace(array('/', '.', '*', '+', '[', ']', '{', '}', "\n", "\r", "\t", '?', '$'), array('\\/', '\\.', '\\*', '\\+', '\\[', '\\]', '\\{', '\\}', '\\s', '\\s', '\\s', '\\?', '\\$'), $match[0]);
			$rematch = preg_replace('/(\\\\s)+/', '\s+', $rematch);
			$rematch = '/' . $rematch . '/si';
			if($match[1] == 'not') {
				if (empty($this->fields[$match[2]])) {
					$output = preg_replace($rematch, $match[3], $output);
				} 
				else {
					$output = preg_replace($rematch, '', $output);
				}
			}
			else {
				if (isset($this->fields[$match[2]])) {
					$output = preg_replace($rematch, $match[3], $output);
				} 
				else {
					$output = preg_replace($rematch, '', $output);
				}
			}
			if($oldoutput==$output) {owd('Template match caused endless loop:', $rematch);die();}
			$oldoutput = $output;
		}
		if($clear) $fields = array();
		return $output;
	}
}

function owd()
{
	global $debug;
	$debug->debug(func_get_args());
}

$debug = new microdebug();

class microdebug
{
	var $timers = array();
	var $debugrevealid = 0;
	
	function debug_reveal($show, $hide) 
	{
		$this->debugrevealid++;
		return "<a href=\"#\" id=\"debugshow-{$this->debugrevealid}\" onclick=\"debugtoggle('debugshow-{$this->debugrevealid}');debugtoggle('debughide-{$this->debugrevealid}');return false;\">$show</a><span style=\"display:none;\" id=\"debughide-{$this->debugrevealid}\">$hide</span>";
	}
	
	function microdebug()
	{
		$this->recordtime('start');
	}
	
	function getmicrotime() 
	{
		list($usec, $sec) = explode(" ", microtime());
		return ((float)$usec + (float)$sec);
	}
	
	function recordtime($s = '')
	{
		if($s == '') $s = count($this->timers);
		$this->timers[$s] = $this->getmicrotime();		
	}
	
	function showtimers()
	{
		$timers = $this->timers;
		$timers['now'] = $this->getmicrotime();
		$start = $timers['start'];
		$timers = array_map(create_function('$a', 'return $a - ' . $start . ';'), $timers);
		$this->debug(array($timers));
	}
	
	function exectime()
	{
		return $this->getmicrotime() - $this->timers['start'];
	}
	
	function debug($argarray)
	{
		$fooargs = $argarray; //func_get_args();
		echo "<div style=\"background-color:#ffeeee;border:1px solid red;text-align:left;\">";
		if(function_exists('debug_backtrace')) {
			$output = "<script type=\"text/javascript\">
			debuggebi = function(id) {return document.getElementById(id);}
			debugtoggle = function(id) {debuggebi(id).style.display = debuggebi(id).style.display=='none'?'':'none';}
			</script>
			<table style=\"background-color:#fff8f8;\">";
			$backtrace = array_reverse(debug_backtrace(), true);
			foreach($backtrace as $trace) {
				$file = $line = $class = $type = $function = '';
				extract($trace);
				if(isset($class))	$fname = $class . $type . $function; else	$fname = $function;
				if(!isset($file) || $file=='') $file = '[Internal PHP]'; else $file = basename($file);
					
				$output .= "<tr><td style=\"padding-left: 10px;\">{$file} ({$line}):</td><td style=\"padding-left: 20px;white-space: pre;font-family:Courier New,Courier,monospace\">{$fname}(";
				$comma = '';
				foreach((array)$args as $arg) { $output .= $comma . $this->debug_reveal(gettype($arg), htmlentities(print_r($arg,1))); $comma = ', '; }
				$output .= ");</td></tr>"; 
			}
			$output .= "</table>";
			echo $this->debug_reveal('[Show Call Stack]', $output);
		}
		echo "<pre>";
		foreach($fooargs as $arg1)
		{
			echo htmlentities(print_r($arg1, 1)) . "<br/>";
		}
		echo "</pre></div>";
	}
}

function dowd($errno, $errstr, $errfile, $errline)
{
	new microdebug(array($errstr, "Line {$errline} of {$errfile}"));
}

//set_error_handler('dowd', E_ALL & ~E_NOTICE);